home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
AECUR100.ARJ
/
PMENUOBJ.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-08
|
7KB
|
368 lines
/*------------------------------------------------------------
*
* pmenuobj.c
*
* Popup MENU OBJect
*
* copyright (c) 1988,89,90 J. Alan Eldridge
*
*----------------------------------------------------------*/
#include "curses.h"
extern WINDOW *newwin(), *subwin(), *savescr();
/* constructor function */
int
pm_ctor(this, id, y, x, title, maxr, arr, norm, high)
POPUP_MENU *this;
int id, y, x;
char *title;
int maxr;
char **arr;
int norm, high;
{
int r, c, scroll;
/* count items & determine window size */
this->itemcnt = scrollmsize(title, maxr, arr, &r, &c, &scroll);
if (this->itemcnt == 0)
return ERR;
/* set default origin if asked to */
if (y < 0 || x < 0) {
getyx(curscr, y, x);
calcpopyx(r, c, y, x, x, &y, &x);
}
/* try to allocate window including frame */
if (!(this->box = newwin(r, c, y, x)))
return ERR;
/* set attributes if necessary & possible */
if (iscolor()) {
if (norm != -1)
setnorm(this->box, norm);
if (high != -1)
setstand(this->box, high);
wstandend(this->box);
}
/* get a subwindow for the items */
if (!(this->win = subwin(this->box, r - 2, c - 2, y + 1, x + 1))) {
delwin(this->box);
return ERR;
}
/* save what's under the window */
if (!(this->save = savescr(r, c, y, x))) {
delwin(this->win);
delwin(this->box);
return ERR;
}
scrollok(this->win, 0);
wrapok(this->win, 0);
box(this->box, 0, 0);
if (title)
mvwaddstr(this->box, 0, 1, title);
if (scroll) {
mvwaddch(this->box, 1, getmaxc(this->box), CH_UPARROW);
mvwaddch(this->box, getmaxr(this->box) - 1,
getmaxc(this->box), CH_DNARROW);
}
this->itemlist = arr;
this->curitem = this->topitem = 1;
this->id = id;
return OK;
}
/* destructor function : also restores screen */
void
pm_dtor(this)
POPUP_MENU *this;
{
delwin(this->win);
delwin(this->box);
restscr(this->save);
delwin(this->save);
}
/*
calculate size needed by popup menu window
and whether or not menu needs to scroll
returns # of items in array
*/
int
scrollmsize(title, maxr, arr, rp, cp, scrollp)
char *title;
int maxr;
char **arr;
int *rp, *cp, *scrollp;
{
int icnt, ccnt, ilen;
icnt = 0;
ccnt = title ? strlen(title) : 0;
while (*arr) {
icnt++;
ilen = strlen(*arr);
if (ilen > ccnt)
ccnt = ilen;
arr++;
}
if (maxr > 0 && maxr < icnt) {
*scrollp = 1;
*rp = maxr + 2;
} else {
*scrollp = 0;
*rp = icnt + 2;
}
*cp = ccnt + 4;
return icnt;
}
int
popmsize(title, arr, rp, cp)
char *title, **arr;
int *rp, *cp;
{
int dummy;
return scrollmsize(title, -1, arr, rp, cp, &dummy);
}
/* draw popup menu with current item highlighted */
void
pm_draw(this)
POPUP_MENU *this;
{
int r, rcnt, aidx, cidx;
rcnt = getmaxr(this->win) + 1;
aidx = this->topitem - 1;
cidx = this->curitem - 1;
for (r = 0; rcnt-- > 0; r++, aidx++) {
if (aidx == cidx)
wstandout(this->win);
mvwaddch(this->win, r, 0, ' ');
waddstr(this->win, this->itemlist[aidx]);
wclrtoeol(this->win);
if (aidx == cidx)
wstandend(this->win);
}
touchwin(this->box);
wrefresh(this->box);
}
/* change attributes of a row of a window */
static void
overat(win, row, cnt)
WINDOW *win;
int row, cnt;
{
wmove(win, row, 0);
while (cnt-- > 0)
waddch(win, winch(win));
}
/* set scrolling style */
static int smooth = 1;
void
pm_smooth(flag)
int flag;
{
smooth = flag;
}
/* highlight next item, scrolling if necessary */
void
pm_next(this, redraw_flag)
POPUP_MENU *this;
int redraw_flag;
{
int rcnt, ccnt, crow;
if (this->curitem == this->itemcnt) {
/* beep(); */
return;
}
getmaxrc(this->win, rcnt, ccnt);
rcnt++;
ccnt++;
this->curitem++;
if (this->curitem < this->topitem + rcnt) {
crow = this->curitem - this->topitem;
overat(this->win, crow - 1, ccnt);
wstandout(this->win);
overat(this->win, crow, ccnt);
wstandend(this->win);
if (redraw_flag)
wrefresh(this->win);
} else {
/* must scroll up */
if (smooth)
this->topitem++;
else {
this->topitem += rcnt - 1;
if (this->topitem + rcnt - 1 > this->itemcnt)
this->topitem = this->itemcnt - rcnt + 1;
}
if (redraw_flag)
pm_draw(this);
}
}
/* highlight previous item, scrolling if necessary */
void
pm_prev(this, redraw_flag)
POPUP_MENU *this;
int redraw_flag;
{
int rcnt, ccnt, crow;
if (this->curitem == 1) {
/*beep();*/
return;
}
getmaxrc(this->win, rcnt, ccnt);
rcnt++;
ccnt++;
this->curitem--;
if (this->curitem >= this->topitem) {
crow = this->curitem - this->topitem;
overat(this->win, crow + 1, ccnt);
wstandout(this->win);
overat(this->win, crow, ccnt);
wstandend(this->win);
if (redraw_flag)
wrefresh(this->win);
} else {
/* must scroll down */
if (smooth)
this->topitem--;
else {
this->topitem -= rcnt - 1;
if (this->topitem < 1)
this->topitem = 1;
}
if (redraw_flag)
pm_draw(this);
}
}
/* user i/o function : returns 0 for abort otherwise choice (first = 1) */
int
pm_choose(this)
POPUP_MENU *this;
{
int c;
pm_draw(this);
hidecursor();
while ((c = wgetch(this->win)) != K_ESC && c != K_NL)
switch (c) {
case K_SPACE:
case K_TAB:
case K_RIGHT:
case K_DOWN:
pm_next(this, 1);
break;
case K_BACK:
case K_LEFT:
case K_UP:
pm_prev(this, 1);
break;
default:
beep();
break;
}
showcursor();
return c == K_ESC ? 0 : this->curitem;
}
/*
set the current item pointer
this is a pessimal implementation ...
(make it work, then make it fast - kernighan)
*/
int
pm_select(this, item_num)
POPUP_MENU *this;
int item_num;
{
int cur_item = this->curitem;
int item_cnt = this->itemcnt;
if (item_num > item_cnt || item_num < 1)
return ERR;
/*
notice that at most one of these
while loops will execute
*/
while (cur_item > item_num) {
cur_item--;
pm_prev(this, 0);
}
while (cur_item++ < item_num)
pm_next(this, 0);
return OK;
}
/* return the itemlist pointer */
char **
pm_itemlist(this)
POPUP_MENU *this;
{
return this->itemlist;
}
/* return the menu id */
int
pm_id(this)
POPUP_MENU *this;
{
return this->id;
}